#include <stdio.h>
#include <stdlib.h>
#include <errno.h> // 需要包含此头文件以使用errno
#include <stdint.h>
#include <string.h> // 用于 strerror 函数
#include <stdbool.h>

#define _PRINT_

typedef struct _t_date_time_
{
    unsigned int year;
    unsigned int month;
    unsigned int date;
    unsigned int hours;
    unsigned int minutes;
    unsigned int seconds;
}t_date_time;

typedef struct _t_device_version_
{
    char product[16];
    char build_time[24];
    char len;
    char version[7];
} t_device_version;

const unsigned char month_str[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov","Dec"};

// 根据传入的字符串返回对应的月份
unsigned char get_month_from_string(unsigned char *temp_str)
{
    // 定义一个变量i，用于循环
    unsigned char i;
    // 遍历12个月份的字符串
    for (i = 0; i < 12; i++)
    {
        // 如果传入的字符串与月份字符串匹配
        if (temp_str[0] == month_str[i][0] && temp_str[1] == month_str[i][1] && temp_str[2] == month_str[i][2])
        {
            // 返回对应的月份
            return i + 1;
        }
    }

    // 如果没有匹配的月份，返回0
    return 0;
}

void string_to_date_time(t_date_time * pt_date_time, const char * date_time)
{
    unsigned char temp_str[4];

    sscanf(date_time, "%s %2d %4d %2d:%2d:%2d", temp_str, &pt_date_time->date, &pt_date_time->year,
                                                &pt_date_time->hours, &pt_date_time->minutes, &pt_date_time->seconds);

    pt_date_time->month = get_month_from_string(temp_str);
}

int main(int argc, char *argv[])
{
#if 1
    if (argc != 4)
    {
        printf("Usage: %s(%d) <char1> <char2> <char3> <int4>\n", argv[0], argc);
        return 1;
    }

    // 第一个是输入为无后缀源文件名
    // 第二个是输入的文件路径
    // 第三个是版本号所在的偏移位置

    char *argv_src_name = argv[1];
    char *argv_src_path = argv[2];
    int read_offset = atoi(argv[3]); // 内容偏移地址
#else
    char *argv_src_name = "Project";
    char *argv_src_path = "G:/release/knowledge_insight_hub/insight_hub/1.IAR_bat/Debug/Exe/";
    int read_offset = 512; // 内容偏移地址
#endif
    t_device_version bin_ver;
    // 组合文件路径
    char src_file_path_bin[1024];

    // file_path里面存的是源bin文件全路径
    snprintf(src_file_path_bin, sizeof(src_file_path_bin), "%s/%s.bin",argv_src_path, argv_src_name);

#ifdef _PRINT_
    printf("[%u]input:%s\n", __LINE__, src_file_path_bin);
#endif

    // 打开文件
    FILE * origin_bin_file = fopen(src_file_path_bin, "rb");
    if (origin_bin_file == NULL)
    {
        perror("Failed to open source_file");
        return 2;
    }

    // 设置文件读取位置，版本信息存在read_offset偏移处
    if (fseek(origin_bin_file, read_offset, SEEK_SET) != 0)
    {
        perror("Failed to seek source_file");
        fclose(origin_bin_file);
        return 2;
    }

    // 读取版本信息
    size_t bytes_read = fread((char *)&bin_ver, 1, sizeof(bin_ver), origin_bin_file);
    if (bytes_read < sizeof(bin_ver))
    {
        if (feof(origin_bin_file)) {
            fprintf(stderr, "[%u]Error %s reading source_file:%s.%lu bytes.\n", __LINE__, strerror(errno), src_file_path_bin, (unsigned long)bytes_read);
            fclose(origin_bin_file);
            return 3;
        } else if (ferror(origin_bin_file)) {
            fprintf(stderr, "[%u]Error %s reading source_file:%s\n", __LINE__, strerror(errno), src_file_path_bin);
            fclose(origin_bin_file);
            return 4;
        }
    }

    char target_bin_name[512];
    int len = 0;
    int max_len = sizeof(target_bin_name);

    // product
    if (bin_ver.product[0] != 0)
    {
        len += snprintf(target_bin_name+len, max_len-len, "%.*s", (int)sizeof(bin_ver.product), bin_ver.product);
    }
    // 版本号
    if (bin_ver.len)
    {
        len += snprintf(target_bin_name+len, max_len-len, "_V");
        uint8_t i = 0;
        for (i=0; i<bin_ver.len-1; i++)
        {
            len += snprintf(target_bin_name+len, max_len-len, "%02x.", bin_ver.version[i]);
        }
        len += snprintf(target_bin_name+len, max_len-len, "%02x", bin_ver.version[i]);
    }
    // 编译日期
    t_date_time date_time;
    string_to_date_time(&date_time, bin_ver.build_time);
    len += snprintf(target_bin_name+len, max_len-len, "_%04d%02d%02d_%02d%02d%02d",
                    date_time.year, date_time.month, date_time.date,
                    date_time.hours, date_time.minutes, date_time.seconds);
#ifdef _PRINT_
    printf("[%u]target:%s\n", __LINE__, target_bin_name);
#endif // _PRINT_

     // **********读取源bin文件内，写到目标文件bin内*********************************************************
    bool write_ok = false;
    uint32_t all_read_len = 0;
    char target_file_path_bin[1024]; // 用于存放目标bin文件全路径
    snprintf(target_file_path_bin, sizeof(target_file_path_bin), "%s/%s.bin", argv_src_path, target_bin_name);
    // 将原始文件读取到内存中，统计长度，计算crc值，然后写入到目标文件中
    if (0 == fseek(origin_bin_file, 0, SEEK_SET))
    { // 先移到-位置
        // 创建目标bin文件
        char buffer_read[256]; // 用于计算crc，256一计算，可以根据实际情况调整
        FILE * target_bin_file = fopen(target_file_path_bin, "w+b"); // 以读写模式打开二进制文件
        if (NULL != target_bin_file)
        {
            size_t bytes_write = 0;
            bytes_read = sizeof(buffer_read);
            do
            {
                bytes_read = fread(buffer_read, 1, sizeof(buffer_read), origin_bin_file);
                if (bytes_read)
                {
                    all_read_len += bytes_read;
                    bytes_write = fwrite(buffer_read, 1, bytes_read, target_bin_file);
                    if (bytes_write != bytes_read)
                    {
                        fprintf(stderr, "[%u]Error %s writing file:%s\n", __LINE__, strerror(errno), target_file_path_bin);
                        break;
                    }
                }
                if (feof(origin_bin_file))
                {
                    write_ok = true;
                    break;
                }
            } while (bytes_read >= sizeof(buffer_read));

            fflush(target_bin_file);
            fprintf(stdout, "[%u]write file:%s.len:%u\n", __LINE__, target_file_path_bin, all_read_len);
            fclose(target_bin_file); // 关闭目标bin文件
        }
        else
        {
            fprintf(stderr, "[%u]Error %s opening file:%s\n", __LINE__, strerror(errno), target_file_path_bin);
        }
    }
    fclose(origin_bin_file); // 关闭源bin文件

    if (write_ok)
    {
        printf("[%u]Generate target file:%s success.len:%u.\n", __LINE__, target_bin_name, all_read_len);
    }
    else
    {
        remove(target_file_path_bin);
        printf("##############################\n");
        printf("[%u]Generate target file:%s fail.\n", __LINE__, target_bin_name);
        printf("##############################\n");
    }

    return 0;
}
